home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / Development Tools & Languages / • Other Platforms / PCCTS / h / AParser.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-14  |  10.3 KB  |  411 lines  |  [TEXT/MPS ]

  1. /* ANTLRParser.C
  2.  *
  3.  * SOFTWARE RIGHTS
  4.  *
  5.  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
  6.  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
  7.  * company may do whatever they wish with source code distributed with
  8.  * PCCTS or the code generated by PCCTS, including the incorporation of
  9.  * PCCTS, or its output, into commerical software.
  10.  * 
  11.  * We encourage users to develop software with PCCTS.  However, we do ask
  12.  * that credit is given to us for developing PCCTS.  By "credit",
  13.  * we mean that if you incorporate our source code into one of your
  14.  * programs (commercial product, research project, or otherwise) that you
  15.  * acknowledge this fact somewhere in the documentation, research report,
  16.  * etc...  If you like PCCTS and have developed a nice tool with the
  17.  * output, please mention that you developed it using PCCTS.  In
  18.  * addition, we ask that this header remain intact in our source code.
  19.  * As long as these guidelines are kept, we expect to continue enhancing
  20.  * this system and expect to make other tools available as they are
  21.  * completed.
  22.  *
  23.  * ANTLR 1.23
  24.  * Terence Parr
  25.  * Parr Research Corporation
  26.  * with Purdue University and AHPCRC, University of Minnesota
  27.  * 1989-1994
  28.  */
  29. #include <stdlib.h>
  30. #include <stdarg.h>
  31. #include <string.h>
  32. #include <stdio.h>
  33.  
  34. /* I have to put this here due to C++ limitation
  35.  * that you can't have a 'forward' decl for enums.
  36.  * I hate C++!!!!!!!!!!!!!!!
  37.  */
  38. enum TokenType { TER_HATES_CPP, ITS_UTTER_GARBAGE, WITH_SOME_GOOD_IDEAS };
  39.  
  40. #include "config.h"
  41. #include ATOKEN_H
  42. #include ATOKENBUFFER_H
  43. #include APARSER_H
  44.  
  45. static const zzINF_DEF_TOKEN_BUFFER_SIZE = 2000;
  46. static const zzINF_BUFFER_TOKEN_CHUNK_SIZE = 1000;
  47.  
  48.                  /* L o o k a h e a d  M a c r o s */
  49.  
  50. /* maximum of 32 bits/unsigned int and must be 8 bits/byte;
  51.  * we only use 8 bits of it.
  52.  */
  53. SetWordType ANTLRParser::bitmask[sizeof(SetWordType)*8] = {
  54.     0x00000001, 0x00000002, 0x00000004, 0x00000008,
  55.     0x00000010, 0x00000020, 0x00000040, 0x00000080
  56. };
  57.  
  58. char ANTLRParser::eMsgBuffer[500] = "";
  59.  
  60. ANTLRParser::
  61. ~ANTLRParser()
  62. {
  63.     delete [] token_type;
  64. }
  65.  
  66. ANTLRParser::
  67. ANTLRParser(ANTLRTokenBuffer *inputTokens,
  68.             int k,
  69.             int use_inf_look,
  70.             int dlook,
  71.             int ssize)
  72. {
  73.     LLk = k;
  74.     can_use_inf_look = use_inf_look;
  75.     demand_look = dlook;
  76.     bsetsize = ssize;
  77.  
  78.     guessing = 0;
  79.     token_tbl = NULL;
  80.     eofToken = (TokenType)1;
  81.  
  82.     // allocate lookahead buffer
  83.     token_type = new TokenType[LLk];
  84.     lap = 0;
  85.     labase = 0;
  86.  
  87.     /* prime lookahead buffer, point to inputTokens */
  88.     this->inputTokens = inputTokens;
  89.     this->inputTokens->setMinTokens(k);
  90. }
  91.  
  92. void ANTLRParser::init()
  93. {
  94.    prime_lookahead();
  95. }
  96.  
  97. int ANTLRParser::
  98. guess(ANTLRParserState *st)
  99. {
  100.     saveState(st);
  101.     guessing = 1;
  102.     return setjmp(guess_start.state);
  103. }
  104.  
  105. void ANTLRParser::
  106. saveState(ANTLRParserState *buf)
  107. {
  108.     buf->guess_start = guess_start;
  109.     buf->guessing = guessing;
  110.     buf->inf_labase = inf_labase;
  111.     buf->inf_last = inf_last;
  112.     buf->dirty = dirty;
  113. }
  114.  
  115. void ANTLRParser::
  116. restoreState(ANTLRParserState *buf)
  117. {
  118.     int i;
  119.  
  120.     guess_start = buf->guess_start;
  121.     guessing = buf->guessing;
  122.     inf_labase = buf->inf_labase;
  123.     inf_last = buf->inf_last;
  124.     dirty = buf->dirty;
  125.  
  126.     // restore lookahead buffer from k tokens before restored TokenBuffer position
  127.     // if demand_look, then I guess we don't look backwards for these tokens.
  128.     for (i=1; i<=LLk; i++) token_type[i-1] =
  129.         ((ANTLRTokenBase *)inputTokens->bufferedToken(i-LLk))->getType();
  130.     lap = 0;
  131.     labase = 0;
  132. }
  133.  
  134. /* Get the next symbol from the input stream; put it into lookahead buffer;
  135.  * fill token_type[] fast reference cache also.  NLA is the next place where
  136.  * a lookahead ANTLRTokenBase should go.
  137.  */
  138. void ANTLRParser::
  139. consume()
  140. {
  141.     NLA = ((ANTLRTokenBase *)inputTokens->getToken())->getType();
  142.     dirty--;
  143.     lap = (lap+1)&(LLk-1);
  144. }
  145.  
  146. ANTLRTokenBase *ANTLRParser::
  147. LT(int i)
  148. {
  149. #ifdef DEBUG_TOKENBUFFER
  150.     if ( i >= inputTokens->bufferSize() || inputTokens->minTokens() <= LLk )
  151.     {
  152.         static char buf[2000];
  153.         sprintf(buf, "The minimum number of tokens you requested that the\nANTLRTokenBuffer buffer is not enough to satisfy your\nLT(%d) request; increase 'k' argument to constructor for ANTLRTokenBuffer\n", i);
  154.         panic(buf);
  155.     }
  156. #endif
  157.     return (ANTLRTokenBase *) inputTokens->bufferedToken(i-LLk);
  158. }
  159.  
  160. void
  161. ANTLRParser::
  162. look(int k)
  163. {
  164.     int i;
  165.     for (i=1; i<=k-(LLk-dirty); i++) consume();
  166. }
  167.  
  168. /* fill the lookahead buffer up with k symbols (even if DEMAND_LOOK);
  169.  */
  170. void
  171. ANTLRParser::
  172. prime_lookahead()
  173. {
  174.     int i;
  175.     for(i=1;i<=LLk; i++) consume();
  176.     dirty=0;
  177.     lap = 0;
  178.     labase = 0;
  179. }
  180.  
  181. /* check to see if the current input symbol matches '_t'.
  182.  * During NON demand lookahead mode, dirty will always be 0 and
  183.  * hence the extra code for consuming tokens in _match is never
  184.  * executed; the same routine can be used for both modes.
  185.  */
  186. int ANTLRParser::
  187. _match(TokenType _t, ANTLRChar **MissText,
  188.        TokenType *MissTok, ANTLRLightweightToken **BadTok,
  189.        SetWordType **MissSet)
  190. {
  191.     if ( dirty==LLk ) {
  192.         consume();
  193.     }
  194.     if ( LA(1)!=_t ) {
  195.         *MissText=NULL;
  196.         *MissTok= _t; *BadTok = LT(1);
  197.         *MissSet=NULL;
  198.         return 0;
  199.     }
  200.     dirty++;
  201.     labase = (labase+1)&(LLk-1);    // labase maintained even if !demand look
  202.     return 1;
  203. }
  204.  
  205. /* check to see if the current input symbol matches any token in a set.
  206.  * During NON demand lookahead mode, dirty will always be 0 and
  207.  * hence the extra code for consuming tokens in _match is never
  208.  * executed; the same routine can be used for both modes.
  209.  */
  210. int ANTLRParser::
  211. _setmatch(SetWordType *tset, ANTLRChar **MissText,
  212.        TokenType *MissTok, ANTLRLightweightToken **BadTok,
  213.        SetWordType **MissSet)
  214. {
  215.     if ( dirty==LLk ) {
  216.         consume();
  217.     }
  218.     if ( !set_el(LA(1), tset) ) {
  219.         *MissText=NULL;
  220.         *MissTok= (TokenType)0; *BadTok=LT(1);
  221.         *MissSet=tset;
  222.         return 0;
  223.     }
  224.     dirty++;
  225.     labase = (labase+1)&(LLk-1);    // labase maintained even if !demand look
  226.     return 1;
  227. }
  228.  
  229. void ANTLRParser::
  230. resynch(SetWordType *wd,SetWordType mask)
  231. {
  232.     static int consumed = 1;
  233.  
  234.     /* if you enter here without having consumed a token from last resynch
  235.      * force a token consumption.
  236.      */
  237.     if ( !consumed ) {consume(); return;}
  238.  
  239.     /* if current token is in resynch set, we've got what we wanted */
  240.     if ( wd[LA(1)]&mask || LA(1) == eofToken ) {consumed=0; return;}
  241.     
  242.     /* scan until we find something in the resynch set */
  243.     while ( !(wd[LA(1)]&mask) && LA(1) != eofToken ) {consume();}
  244.     consumed=1;
  245. }
  246.  
  247. /* standard error reporting function that assumes DLG-based scanners;
  248.  * you should redefine in subclass to change it or if you use your
  249.  * own scanner.
  250.  */
  251. void ANTLRParser::
  252. syn(ANTLRTokenBase *tok, ANTLRChar *egroup, SetWordType *eset,
  253.     TokenType etok, int k)
  254. {
  255.     int line;
  256.  
  257.     line = ((ANTLRTokenBase *)LT(1))->line();
  258.  
  259.     fprintf(stderr, "line %d: syntax error at \"%s\"",
  260.                     line, ((ANTLRTokenBase *)LT(1))->getText());
  261.     if ( !etok && !eset ) {fprintf(stderr, "\n"); return;}
  262.     if ( k==1 ) fprintf(stderr, " missing");
  263.     else
  264.     {
  265.         fprintf(stderr, "; \"%s\" not", ((ANTLRTokenBase *)LT(1))->getText());
  266.         if ( set_deg(eset)>1 ) fprintf(stderr, " in");
  267.     }
  268.     if ( set_deg(eset)>0 ) edecode(eset);
  269.     else fprintf(stderr, " %s", token_tbl[etok]);
  270.     if ( strlen(egroup) > 0 ) fprintf(stderr, " in %s", egroup);
  271.     fprintf(stderr, "\n");
  272. }
  273.  
  274. /* is b an element of set p? */
  275. int ANTLRParser::
  276. set_el(TokenType b, SetWordType *p)
  277. {
  278.     return( p[DIVWORD(b)] & bitmask[MODWORD(b)] );
  279. }
  280.  
  281. int ANTLRParser::
  282. set_deg(SetWordType *a)
  283. {
  284.     /* Fast compute degree of a set... the number
  285.        of elements present in the set.  Assumes
  286.        that all word bits are used in the set
  287.     */
  288.     register SetWordType *p = a;
  289.     register SetWordType *endp = &(a[bsetsize]);
  290.     register int degree = 0;
  291.  
  292.     if ( a == NULL ) return 0;
  293.     while ( p < endp )
  294.     {
  295.         register SetWordType t = *p;
  296.         register SetWordType *b = &(bitmask[0]);
  297.         do {
  298.             if (t & *b) ++degree;
  299.         } while (++b < &(bitmask[sizeof(SetWordType)*8]));
  300.         p++;
  301.     }
  302.  
  303.     return(degree);
  304. }
  305.  
  306. void ANTLRParser::
  307. edecode(SetWordType *a)
  308. {
  309.     register SetWordType *p = a;
  310.     register SetWordType *endp = &(p[bsetsize]);
  311.     register unsigned e = 0;
  312.  
  313.     if ( set_deg(a)>1 ) fprintf(stderr, " {");
  314.     do {
  315.         register SetWordType t = *p;
  316.         register SetWordType *b = &(bitmask[0]);
  317.         do {
  318.             if ( t & *b ) fprintf(stderr, " %s", token_tbl[e]);
  319.             e++;
  320.         } while (++b < &(bitmask[sizeof(SetWordType)*8]));
  321.     } while (++p < endp);
  322.     if ( set_deg(a)>1 ) fprintf(stderr, " }");
  323. }
  324.  
  325. /* input looks like:
  326.  *      zzFAIL(k, e1, e2, ...,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk)
  327.  * where the zzMiss stuff is set here to the token that did not match
  328.  * (and which set wasn't it a member of).
  329.  */
  330. void
  331. ANTLRParser::FAIL(int k, ...)
  332. {
  333.     static char text[1000];    // dangerous, but I don't care right now
  334.     static SetWordType *f[20];
  335.     SetWordType **miss_set;
  336.     ANTLRChar **miss_text;
  337.     ANTLRLightweightToken **bad_tok;
  338.     ANTLRChar **bad_text;
  339.     unsigned *err_k;
  340.     int i;
  341.     va_list ap;
  342.  
  343.     va_start(ap, k);
  344.  
  345.     text[0] = '\0';
  346.     if ( k>20 ) panic("FAIL: overflowed buffer");
  347.     for (i=1; i<=k; i++)    /* collect all lookahead sets */
  348.     {
  349.         f[i-1] = va_arg(ap, SetWordType *);
  350.     }
  351.     for (i=1; i<=k; i++)    /* look for offending token */
  352.     {
  353.         if ( i>1 ) strcat(text, " ");
  354.         strcat(text, ((ANTLRTokenBase *)LT(i))->getText());
  355.         if ( !set_el(LA(i), f[i-1]) ) break;
  356.     }
  357.     miss_set = va_arg(ap, SetWordType **);
  358.     miss_text = va_arg(ap, ANTLRChar **);
  359.     bad_tok = va_arg(ap, ANTLRLightweightToken **);
  360.     bad_text = va_arg(ap, ANTLRChar **);
  361.     err_k = va_arg(ap, unsigned *);
  362.     if ( i>k )
  363.     {
  364.         /* bad; lookahead is permutation that cannot be matched,
  365.          * but, the ith token of lookahead is valid at the ith position
  366.          * (The old LL sub 1 (k) versus LL(k) parsing technique)
  367.          */
  368.         *miss_set = NULL;
  369.         *miss_text = ((ANTLRTokenBase *)(LT(1)))->getText();
  370.         *bad_tok = LT(1);
  371.         *bad_text = ((ANTLRTokenBase *)(*bad_tok))->getText();
  372.         *err_k = k;
  373.         return;
  374.     }
  375. /*  fprintf(stderr, "%s not in %dth set\n", zztokens[LA(i)], i);*/
  376.     *miss_set = f[i-1];
  377.     *miss_text = text;
  378.     *bad_tok = LT(i);
  379.     *bad_text = ((ANTLRTokenBase *)(*bad_tok))->getText();
  380.     if ( i==1 ) *err_k = 1;
  381.     else *err_k = k;
  382. }
  383.  
  384. char *ANTLRParser::
  385. eMsgd(char *err,int d)
  386. {
  387.     sprintf(eMsgBuffer, err, d);    // dangerous, but I don't care
  388.     return eMsgBuffer;
  389. }
  390.  
  391. char *ANTLRParser::
  392. eMsg(char *err, char *s)
  393. {
  394.     sprintf(eMsgBuffer, err, s);
  395.     return eMsgBuffer;
  396. }
  397.  
  398. char *ANTLRParser::
  399. eMsg2(char *err,char *s, char *t)
  400. {
  401.     sprintf(eMsgBuffer, err, s, t);
  402.     return eMsgBuffer;
  403. }
  404.  
  405. void ANTLRParser::
  406. panic(char *msg)
  407. {
  408.     fprintf(stderr, "ANTLR panic: %s\n", msg);
  409.     exit(-1);
  410. }
  411.